Skip to content

WIP: Add concurrent request rate limiter and optimize middleware stack - #5361

Open
serdarozerr wants to merge 10 commits into
cloudfoundry:mainfrom
sap-contributions:feature/concurrent-ratelimiter
Open

serdarozerr wants to merge 10 commits into
cloudfoundry:mainfrom
sap-contributions:feature/concurrent-ratelimiter

Conversation

@serdarozerr

@serdarozerr serdarozerr commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Concurrent request rate limiter: Introduced ConcurrencyRateLimiter middleware that limits the number of concurrent in-flight requests per user (or IP for unauthenticated requests). Supports separate logging_limit (warn only) and blocking_limit (return 429) for smooth rollout. Disabled by default via config. Backed by Redis (with TTL-based safety cleanup) or in-memory store for single-process deployments. Admins are rate limited the same as regular users.

Middleware stack optimization: Split SecurityContextSetter into two concerns — token decoding only (configure_token_only) happens early in the stack, and user DB lookup (configure_user) is deferred to a new UserContextSetter middleware placed after rate limiters. This means rate limiting never triggers a DB lookup for blocked requests. RequestMetrics is also moved after rate limiters so that blocked 429 responses are excluded from request metrics, keeping metrics focused on requests that actually reached the application.

Changes

  • middleware/concurrency_rate_limiter.rb — new middleware with ConcurrencyRateLimiter, ConcurrencyLimiter, ConcurrentRedisStore, ConcurrentInMemoryStore
  • middleware/user_context_setter.rb — new middleware for deferred user DB lookup
  • middleware/security_context_setter.rb — now calls configure_token_only instead of full configure
  • lib/cloud_controller/security/security_context_configurer.rb — added configure_token_only and configure_user methods
  • lib/cloud_controller/rack_app_builder.rb — wired new middlewares, moved RequestMetrics after rate limiters
  • lib/cloud_controller/config_schemas/api_schema.rb — added concurrency_rate_limiter config schema
  • Retry-After header added on 429 responses from the concurrent rate limiter.

… done.

Introduces ConcurrencyRateLimiter middleware to limit concurrent requests
per user across all endpoints. Supports separate logging and blocking
thresholds for smooth rollout, Redis and in-memory store backends,
thread-safe singleton limiter instance, and RetryAfter header estimation
based on request duration. Disabled by default via config.

Also separates user DB lookup from token decoding into a dedicated
UserContextSetter middleware, and moves RequestMetrics after rate limiters
in the middleware stack.
Comment thread lib/cloud_controller/security/security_context_configurer.rb Outdated
Comment thread lib/cloud_controller/security_context.rb Outdated
Comment thread lib/cloud_controller/security/security_context_configurer.rb
Comment thread spec/unit/middleware/user_context_setter_spec.rb Outdated
Comment thread spec/unit/lib/cloud_controller/security/security_context_configurer_spec.rb Outdated
Comment thread middleware/concurrency_rate_limiter.rb Outdated
Comment thread middleware/concurrency_rate_limiter.rb Outdated
Comment thread config/cloud_controller.yml
Comment thread middleware/concurrency_rate_limiter.rb Outdated

module VCAP::CloudController
class RackAppBuilder
# rubocop:disable Metrics/MethodLength, Metrics/BlockLength

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could refactor this in order to reduce the method length...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactoring is possible but would require removing the builder block and introducing extra methods, which might hurts readability. So i thought better to keep current form since the full middleware stack is visible in order in one place.

stephanme added a commit that referenced this pull request Sep 15, 2026
- implementation on #5361 was improved and reaches more throughput now
- all measurements run for 300s
- more detailed explanation how to determine max throughput
- some more arguments for replacing nginx by a dedicated CAPI router
- Introduce ConcurrentRequestCounter with InMemoryStore and RedisStore
  backends using atomic Lua scripts for check-and-increment; rejected
  requests do not increment the counter (no phantom count)
- Add ConcurrencyRateLimiter and ServiceBrokerRateLimiter middlewares
  backed by the new counter
- Extract UserId, InternalOrRootApi, TooManyRequests, BasicAuth mixins
- Derive redis_connection_pool_size and redis_counter_ttl_seconds from
  puma max_threads and request_timeout_in_seconds in config
- Add unit tests for all new components
@serdarozerr serdarozerr changed the title Add concurrent request rate limiter and optimize middleware stack WIP: Add concurrent request rate limiter and optimize middleware stack Sep 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants